#include <unistd.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "hook_helper.h"
#include "hook_interface.h"

socket_t socket_f = NULL;
close_t close_f = NULL;
connect_t connect_f = NULL;
accept_t accept_f = NULL;
read_t read_f = NULL;
write_t write_f = NULL;
send_t send_f = NULL;
recv_t recv_f = NULL;
poll_t poll_f = NULL;
sleep_t sleep_f = NULL;
usleep_t usleep_f = NULL;
getsockopt_t getsockopt_f = NULL;
setsockopt_t setsockopt_f = NULL;
fcntl_t fcntl_f = NULL;
pipe_t pipe_f = NULL;

int socket(int domain, int type, int protocol)
{
    return Singleton<HookRealize>::instance()->socket(domain, type, protocol);
}

int close(int fd)
{
    return Singleton<HookRealize>::instance()->close(fd);
}

int connect(int fd, const sockaddr* addr, socklen_t addrlen)
{
    return Singleton<HookRealize>::instance()->connect(fd, addr, addrlen);
}

int accept(int fd, struct sockaddr* addr, socklen_t* addrlen)
{
    return Singleton<HookRealize>::instance()->accept(fd, addr, addrlen);
}

ssize_t read(int fd, void* buf, size_t len)
{
    return Singleton<HookRealize>::instance()->read(fd, buf, len);
}

ssize_t write(int fd, const void* buf, size_t len)
{
    return Singleton<HookRealize>::instance()->write(fd, buf, len);
}

ssize_t send(int fd, const void* buf, size_t len, int flags)
{
    return Singleton<HookRealize>::instance()->send(fd, buf, len, flags);
}

ssize_t recv(int fd, void* buf, size_t len, int flags)
{
    return Singleton<HookRealize>::instance()->recv(fd, buf, len, flags);
}

int poll(struct pollfd* fds, nfds_t nfds, int timeout)
{
    return Singleton<HookRealize>::instance()->poll(fds, nfds, timeout);
}

unsigned int sleep(unsigned int seconds)
{
    return Singleton<HookRealize>::instance()->sleep(seconds);
}

int usleep(useconds_t usec)
{
    return Singleton<HookRealize>::instance()->usleep(usec);
}

int getsockopt(int fd, int level, int optname, void* optval, socklen_t* optlen)
{
    return Singleton<HookRealize>::instance()->getsockopt(fd, level, optname, optval, optlen);
}

int setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen)
{
    return Singleton<HookRealize>::instance()->setsockopt(fd, level, optname, optval, optlen);
}

int fcntl(int fd, int cmd, ...)
{
    int ret = 0;

    va_list va;
    va_start(va, cmd);

    switch (cmd) {
        case F_DUPFD:
        case F_DUPFD_CLOEXEC:
        case F_SETFD:
        case F_SETOWN:
        case F_SETSIG:
        case F_SETLEASE:
        case F_NOTIFY:
        case F_SETPIPE_SZ:
        case F_SETFL:
            {
                int arg = va_arg(va, int);
                va_end(va);
                ret = Singleton<HookRealize>::instance()->fcntl(fd, cmd, arg);
                break ;
            }
        case F_GETLK:
        case F_SETLK:
        case F_SETLKW:
            {
                struct flock* arg = va_arg(va, struct flock*);
                va_end(va);
                ret = Singleton<HookRealize>::instance()->fcntl(fd, cmd, arg);
                break ;
            }
        case F_GETOWN_EX:
        case F_SETOWN_EX:
            {
                struct f_owner_exlock* arg = va_arg(va, struct f_owner_exlock*);
                va_end(va);
                ret = Singleton<HookRealize>::instance()->fcntl(fd, cmd, arg);
                break ;
            }
        case F_GETFL:
        case F_GETOWN:
        case F_GETSIG:
        case F_GETLEASE:
        default:
            {
                va_end(va);
                ret = Singleton<HookRealize>::instance()->fcntl(fd, cmd);
                break ;
            }
    }
    return ret;
}

int pipe(int pipefd[2])
{
    return Singleton<HookRealize>::instance()->pipe(pipefd);
}

